home *** CD-ROM | disk | FTP | other *** search
/ Multimedia Selection / Multimedia Selection Volume One - CD-ROM / MULTIMEDIA SELECTION____________.ISO / programz / ldb / sbinder.hpp < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-25  |  10.0 KB  |  383 lines

  1. /*
  2.  
  3.     sbinder.hpp
  4.     10-25-91
  5.     Streamable Binder: Loose Data Binder v 1.5
  6.  
  7.     Copyright 1991
  8.     John W. Small
  9.     All rights reserved
  10.  
  11.     PSW / Power SoftWare
  12.     P.O. Box 10072
  13.     McLean, Virginia 22102 8072 USA
  14.  
  15.     John Small
  16.     Voice: (703) 759-3838
  17.     CIS: 73757,2233
  18.  
  19. */
  20.  
  21.  
  22. #ifndef SBINDER_HPP
  23. #define SBINDER_HPP
  24.  
  25. #include <iostream.h>
  26. #include <iomanip.h>
  27.  
  28. #ifndef BINDER_HPP
  29. #include "binder.hpp"
  30. #endif
  31.  
  32. #define ID_Streamable        0
  33. #define ID_StreamableRef    ID_Streamable
  34. #define ID_SBinder        1
  35.  
  36.  
  37. class Streamable;
  38. typedef Streamable * StreamablE;
  39. #define StreamablE0 ((StreamablE)0)
  40.  
  41. class StreamableClassRegistry;
  42. #define SCRegistry  SCReg
  43. extern StreamableClassRegistry SCRegistry;
  44.  
  45. /*
  46.  
  47.     A class must include the STREAMABLE macro or its
  48.     equivalent in its public section and be derived 
  49.     either publicly or privately from Streamable but 
  50.     never virtually or otherwise multiply inherited 
  51.     in order for it to be "streamable".  Furthermore 
  52.     it must have been linked to.  The SBinder 
  53.     primitives automatically link to and unlink from 
  54.     Streamable nodes.  That means the SBinder must
  55.     itself be linked before it can be streamed.  See
  56.     SBinder below or CBinder for an example without 
  57.     using the STREAMABLE macro and SData for an 
  58.     example using STREAMABLE.
  59.  
  60. */
  61.  
  62. class Streamable  {
  63.     friend StreamableClassRegistry;
  64.     voiD parenT;
  65.     unsigned id;
  66.     unsigned refCount, streamCount;
  67.     long streamPos;
  68. /*
  69.     Stream contents:
  70.  
  71.             1st & Only    1st of Many    MultiRef
  72.  
  73.     id        x               x        0
  74.     refCount    1        > 1
  75.     streamCount
  76.     streamPos                    x
  77.     user's data    x        x
  78. */
  79. protected:
  80.     // Static so that the static load() can call!
  81.     static void lserror(const char *msg, unsigned id);
  82.     virtual void serror(const char *msg);
  83.     virtual void swarn(const char *msg);
  84.     virtual ostream& store(ostream& os)
  85.         { return os; }
  86.         // Override to store your data members!
  87.     static StreamablE load(istream& is,
  88.         StreamablE InstancE);
  89.         // Override - see documentation or hack it
  90.         // from SBinder::load, SData::load, or
  91.         // CBinder::load!
  92.     void setID(unsigned id)
  93.         { this->id = id; }
  94. public:
  95.     static int refDebug;
  96.     static int streamDebug;
  97.     static char memberTermChar;
  98.     enum { ID_CLASS = 0 };
  99.     // The first parameter below, "dummy", insures that
  100.     // the STREAMABLE macro defines a unique constructor
  101.     // for derived classes!
  102.     Streamable(StreamableClassRegistry& dummy,
  103.         unsigned id = Streamable::ID_CLASS);
  104.     static void registerClass(unsigned id = ID_CLASS,
  105.         StreamablE (*loader)(istream& is,
  106.         StreamablE InstancE) = load);
  107.     operator StreamablE() { return this; }
  108.     voiD ParenT()  { return parenT; }
  109.     unsigned ID()  { return id; }
  110.     virtual unsigned restream();
  111.     unsigned unlink(voiD P = voiD0);
  112.     StreamablE link(voiD P = voiD0);
  113.     unsigned RefCount()  { return refCount; }
  114.     virtual ~Streamable() {}
  115. };
  116.  
  117.  
  118. // stream manipulator: insert end of member field char
  119.  
  120. extern ostream& endm(ostream& os);
  121.  
  122. // stream manipulator: extract end of member field char
  123.  
  124. extern istream& nextm(istream& is);
  125.  
  126.  
  127. /*
  128.     The STREAMABLE macro declares two functions: store()
  129.     and load() which you must define to store member
  130.     data onto a stream and to load that data back from
  131.     that stream.  You must assign a unique id to each
  132.     streamable class and register every class that will
  133.     be stored on a stream.  Don't forget to restream()
  134.     between operations!
  135. */
  136.  
  137. #define STREAMABLE(class, id, base) \
  138. private:  \
  139.     friend StreamableClassRegistry;  \
  140. protected:  \
  141.     base :: lserror;  \
  142.     base :: serror;  \
  143.     base :: swarn;  \
  144.     virtual ostream& store(ostream& os);  \
  145.     static StreamablE load(istream& is,  \
  146.         StreamablE InstancE);  \
  147.     base :: setID;  \
  148. public:  \
  149.     enum { ID_CLASS = id };  \
  150.     class (StreamableClassRegistry& dummy,  \
  151.         unsigned cid = class ::ID_CLASS) \
  152.         : base (dummy,cid) {}  \
  153.     operator StreamablE()  \
  154.         { return (StreamablE)this; }  \
  155.     static void registerClass(unsigned cid =   \
  156.         class ::ID_CLASS,  \
  157.         StreamablE (*loader)(istream& is,  \
  158.         StreamablE InstancE) = class ::load)  \
  159.         { base :: registerClass(cid,loader); }  \
  160.     base :: ParenT;  \
  161.     base :: ID;  \
  162.     base :: restream;  \
  163.     base :: unlink;  \
  164.     base :: link;  \
  165.     base :: RefCount
  166.     
  167.  
  168. //  value for dummy parameter of constructor above
  169.  
  170. #define UNIQUE_STREAMABLE  SCRegistry
  171.  
  172.  
  173. /*
  174.     SBinder nodes MUST be derived from Streamable,
  175.     e.g. SData, since Dfree(), Dattach(), and Ddetach()
  176.     have been overriden to handle Streamable nodes.  
  177.     Besides adding streamability to a Binder and its
  178.     nodes, Streamable nodes have built in protection 
  179.     against accidental deletion even when the 
  180.     BDR_OK_FREE flag is set since Streamable decendents
  181.     report to SBinder::Dfree() if it's okay to delete. 
  182.     Streamable nodes are only stored once in any single
  183.     streaming operation while multiple references when
  184.     encountered are stored simply as that, multiple 
  185.     references.  When reloading, multiple references to
  186.     nodes are automatically reconstructed as links.  
  187.     This arrangement prevents storing a multiply 
  188.     referenced node multiple times on a stream and 
  189.     subsequently reloading multiple copies instead of 
  190.     correctly reconstructing the links.  Consider a
  191.     SBinder that contains nodes, some of which may be
  192.     SBinders themselves, perhaps rereferencing other
  193.     data nodes and it should be apparent to you why 
  194.     multiple reference streaming to necessary.  It is 
  195.     also possible to have a otherwise streamable SBinder 
  196.     binding nodes not derived from Streamable, see 
  197.     CBinder.
  198.     
  199.     The SBinder header may be statically or dynamically
  200.     allocated.  The nodes must all be either static or 
  201.     dynamic as indicated by the BDR_OK_FREE flag.  
  202.     SBinder defaults to dynamically allocated nodes.
  203. */
  204.  
  205. class SBinder : public Binder, public Streamable  {
  206. protected:
  207.     // Binder::construct
  208.     virtual int  Dfree(voiD D);
  209.     virtual int  Dattach(voiD D);
  210.     virtual void Ddetach(voiD D);
  211.     virtual ostream& store(ostream& os);
  212.     static  StreamablE load(istream& is,
  213.         StreamablE InstancE);
  214.     virtual void Dstore(ostream& os, voiD D);
  215.         /*
  216.             Stores node data on the stream.  It
  217.             assumes that nodes are derived from
  218.             Streamable.  If not you must 
  219.             override!
  220.         */
  221.     virtual voiD Dload(istream& is);
  222.             // Loads node data back from stream.
  223. public:
  224.     enum { ID_CLASS = ID_SBinder };
  225.     SBinder(StreamableClassRegistry& dummy,
  226.         unsigned id = ID_CLASS)
  227.         : Binder(OnlyInitBinderVFT),
  228.         Streamable(dummy,id) {}
  229.     SBinder(unsigned flags = BDR_OK_FREE,
  230.         unsigned maxNodes = BDR_MAXNODES,
  231.         unsigned limit = BDR_LIMIT,
  232.         unsigned delta = BDR_DELTA)
  233.         : Binder(flags,maxNodes,limit,delta),
  234.         Streamable(UNIQUE_STREAMABLE,ID_CLASS)
  235.         {}
  236.     SBinder(voiDV argv, int argc = 0,
  237.         unsigned flags = BDR_OK_FREE)
  238.         : Binder(argv,argc,flags),
  239.         Streamable(UNIQUE_STREAMABLE,ID_CLASS)
  240.         {}
  241.     static void registerClass(unsigned id = ID_CLASS,
  242.         StreamablE (*loader)(istream& is,
  243.         StreamablE InstancE) = load)
  244.         { Streamable :: registerClass(id,loader); }
  245.     virtual unsigned restream();
  246.     virtual ~SBinder();
  247. };
  248.  
  249. typedef SBinder * SBindeR;
  250. #define SBindeR0 ((SBindeR)0)
  251.  
  252.  
  253.  
  254. /*
  255.  
  256.     The StreamableClassRegistry holds the records of
  257.     classes and their static load functions.  Load
  258.     functions have to be static because constructors
  259.     don't have addresses in C++.  Store functions are
  260.     virtual and thus can be called automatically.
  261.  
  262. */
  263.  
  264.  
  265. struct StreamableClassRecord {
  266.     unsigned id;
  267.     StreamablE (*load)(istream& is,
  268.         StreamablE InstancE);
  269.     StreamableClassRecord(unsigned id,
  270.         StreamablE (*load)(istream& is,
  271.             StreamablE InstancE))
  272.         { this->id = id; this->load = load; }
  273. };
  274. typedef StreamableClassRecord * SCRecorD;
  275. #define SCRecorD0 ((SCRecorD)0)
  276.  
  277. struct InstanceHoldingRecord  {
  278.     StreamablE InstancE;
  279.     unsigned refCount, streamCount;
  280.     long streamPos;
  281.     InstanceHoldingRecord(StreamablE InstancE,
  282.         unsigned refCount, long streamPos)
  283.     {
  284.         this->InstancE = InstancE;
  285.         this->refCount = refCount;
  286.         streamCount = 1;
  287.         this->streamPos = streamPos;
  288.     }
  289. };
  290. typedef InstanceHoldingRecord * IHRecorD;
  291. #define IHRecorD0 ((IHRecorD)0)
  292.  
  293.  
  294. class StreamableClassRegistry  {
  295.     Binder ClassRecords;
  296.     Binder InstanceLinks;
  297. protected:
  298.     virtual void error(char *msg, unsigned id = 0,
  299.             StreamablE InstancE = StreamablE0);
  300.     virtual void warn(char *msg, unsigned id = 0,
  301.             StreamablE InstancE = StreamablE0);
  302. public:
  303.     static int debug;
  304.     StreamableClassRegistry()
  305.         : ClassRecords(BDR_OK_FREE),
  306.         InstanceLinks(BDR_OK_FREE)
  307.         {}
  308.     unsigned restream();
  309.     void registerClass(unsigned id, StreamablE (*loader)
  310.         (istream& is, StreamablE InstancE));
  311.     void forgetClasses();
  312.     istream& get(istream& is, StreamablE& InstancE);
  313.     ostream& put(ostream& os, StreamablE InstancE);
  314.     ~StreamableClassRegistry() { forgetClasses(); }
  315. };
  316.  
  317. #define RestreamRegistry()  SCRegistry.restream()
  318.  
  319.  
  320. inline istream& operator>>(istream& is, StreamablE& InstancE)
  321. {
  322.     return SCRegistry.get(is,InstancE);
  323. }
  324.  
  325. inline ostream& operator<<(ostream& os, StreamablE InstancE)
  326. {
  327.     return SCRegistry.put(os, InstancE);
  328. }
  329.  
  330.  
  331.  
  332. /*
  333.  
  334.     FncPtrRegistry is provided so that you can stream
  335.     function pointers.
  336.  
  337. */
  338.  
  339. typedef void (*GenericFnC)();
  340. #define GenericFnC0 ((GenericFnC)0)
  341. #define ID_UnknownGenericFnC    0
  342.  
  343. struct StreamableFncPtrRecord {
  344.     unsigned id;
  345.     GenericFnC fnC;
  346.     StreamableFncPtrRecord(unsigned id,
  347.         GenericFnC fnC)
  348.         { this->id = id; this->fnC = fnC; }
  349. };
  350. typedef StreamableFncPtrRecord * SFPRecorD;
  351. #define SFPRecorD0 ((SFPRecorD)0)
  352.  
  353. class StreamableFncPtrRegistry  {
  354.     Binder FncPtrRecords;
  355. public:
  356.     static int debug;
  357. protected:
  358.     virtual void error(char *msg, unsigned id);
  359.     virtual void warn(char *msg, unsigned id);
  360. public:
  361.     StreamableFncPtrRegistry() : FncPtrRecords()  {}
  362.     void registerFunction(unsigned id,
  363.         GenericFnC fnC);
  364.     GenericFnC FnC(unsigned id);
  365.     unsigned ID(GenericFnC fnC);
  366.     ~StreamableFncPtrRegistry()
  367.         { FncPtrRecords.allFree(); }
  368. };
  369.  
  370. #define SFPRegistry  SFPReg
  371.  
  372. extern StreamableFncPtrRegistry SFPRegistry;
  373.  
  374. #define RegisterFunction(id, fnC)  \
  375.         SFPRegistry.registerFunction(id,fnC)
  376. #define FncPtrToID(fnC)  \
  377.         SFPRegistry.ID(fnC)
  378. #define IDtoFncPtr(id)  \
  379.         SFPRegistry.FnC(id)
  380.  
  381.  
  382. #endif
  383.